Topic 1: Designing & Building a Web API
Concept: A Web API lets applications communicate over HTTP. ASP.NET Core builds RESTful APIs using controllers.
Step 1: Create the project
dotnet new webapi -n MyFirstApi
cd MyFirstApi
dotnet run
Step 2: Program.cs configuration
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Topic 2: Designing RESTful Interface
Concept: REST uses HTTP verbs: GET, POST, PUT, DELETE. Routing maps URLs to controllers and actions.
Hands-on: REST controller simulation
This console simulation shows how a RESTful Products API behaves. You can paste it into .NET Fiddle.
using System;
using System.Collections.Generic;
using System.Linq;
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
public class ProductsController
{
private static List<Product> _db = new List<Product>
{
new Product { Id = 1, Name = "Laptop", Price = 1200 },
new Product { Id = 2, Name = "Mouse", Price = 25 }
};
// GET: api/products
public void Get()
{
Console.WriteLine("HTTP 200 OK:");
foreach (var p in _db)
Console.WriteLine($" [{p.Id}] {p.Name} - ${p.Price}");
}
// POST: api/products
public void Post(string name, decimal price)
{
var newProduct = new Product
{
Id = _db.Max(p => p.Id) + 1,
Name = name,
Price = price
};
_db.Add(newProduct);
Console.WriteLine($"HTTP 201 Created: Added '{newProduct.Name}' (ID: {newProduct.Id})");
}
// DELETE: api/products/1
public void Delete(int id)
{
var product = _db.FirstOrDefault(p => p.Id == id);
if (product != null)
{
_db.Remove(product);
Console.WriteLine($"HTTP 204 No Content: Deleted ID {id}");
}
else
{
Console.WriteLine($"HTTP 404 Not Found: ID {id} does not exist.");
}
}
}
public class Program
{
public static void Main()
{
Console.WriteLine("--- Starting Simulated RESTful API ---\n");
var api = new ProductsController();
api.Get();
Console.WriteLine();
api.Post("Keyboard", 75);
Console.WriteLine();
api.Get();
Console.WriteLine();
api.Delete(1);
Console.WriteLine();
api.Delete(99);
}
}
Topic 3: Securing a Web API
Concept: JWT is commonly used. The client authenticates, receives a token, and sends it in the Authorization header.
Generate a JWT token
using System;
using System.Text;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
using System.Security.Claims;
public class Program
{
public static void Main()
{
var secretKey = "ThisIsMySuperSecretKeyForJwtToken123!";
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, "user123"),
new Claim(JwtRegisteredClaimNames.Email, "user@example.com"),
new Claim(ClaimTypes.Role, "Admin")
};
var token = new JwtSecurityToken(
issuer: "MyApp",
audience: "MyAppUsers",
claims: claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: credentials
);
var tokenHandler = new JwtSecurityTokenHandler();
var jwtString = tokenHandler.WriteToken(token);
Console.WriteLine("--- Generated JWT Token ---");
Console.WriteLine(jwtString);
Console.WriteLine("\nClient sends it as: Authorization: Bearer <token>");
}
}
ASP.NET Core JWT setup
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "MyApp",
ValidAudience = "MyAppUsers",
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes("ThisIsMySuperSecretKeyForJwtToken123!"))
};
});
app.UseAuthentication();
app.UseAuthorization();
Topic 4: ASP.NET Core Runtime Environment & Host
Concept: The Generic Host manages startup, dependency injection, logging, configuration, and lifetime.
Host lifecycle simulation
using System;
public class WebApplication
{
public static WebApplicationBuilder CreateBuilder(string[] args)
{
Console.WriteLine("[Host] Creating Builder...");
return new WebApplicationBuilder();
}
public static void Run(string message)
{
Console.WriteLine("[Host] Application Started.");
Console.WriteLine($"[Host] {message}");
Console.WriteLine("[Host] Listening for requests...");
}
}
public class WebApplicationBuilder
{
public void AddServices()
{
Console.WriteLine("[Host] Configuring Dependency Injection...");
Console.WriteLine(" - Registered: ILogger, IConfiguration, Controllers");
}
public void Build()
{
Console.WriteLine("[Host] Building the application pipeline...");
}
}
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.AddServices();
builder.Build();
WebApplication.Run("Host is running on http://localhost:5000");
}
}
Topic 5: Embedded HTTP Server (Kestrel)
Concept: Kestrel is the default cross-platform embedded web server in ASP.NET Core. It is fast, lightweight, and part of the app process.
Configure Kestrel in code
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.Limits.MaxConcurrentConnections = 100;
serverOptions.Limits.MaxRequestBodySize = 10 * 1024 * 1024;
serverOptions.ListenAnyIP(5000);
});
var app = builder.Build();
app.MapGet("/", () => "Hello from Kestrel Embedded Server!");
app.Run();
Configure Kestrel in appsettings.json
{
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:5000"
},
"Https": {
"Url": "https://localhost:5001"
}
}
},
"Logging": {
"LogLevel": {
"Default": "Information"
}
},
"AllowedHosts": "*"
}
Topic 6: ASP.NET Core Middleware
Concept: Middleware components form a request pipeline. Each can process the request, pass it on, or stop it.
Middleware pipeline simulation
using System;
using System.Threading.Tasks;
public class HttpContext
{
public string RequestPath { get; set; } = "/api/data";
}
public delegate Task RequestDelegate(HttpContext context);
public class Program
{
public static async Task Main()
{
Console.WriteLine("--- Starting Middleware Pipeline ---\n");
RequestDelegate middleware1 = async (context) =>
{
Console.WriteLine("[Middleware 1] Request started: " + context.RequestPath);
await Task.CompletedTask;
};
RequestDelegate middleware2 = async (context) =>
{
Console.WriteLine("[Middleware 2] Authenticating...");
Console.WriteLine("[Middleware 2] User Authenticated!");
await Task.CompletedTask;
};
RequestDelegate endpoint = async (context) =>
{
Console.WriteLine("[Endpoint] Processing request...");
Console.WriteLine("[Endpoint] Returning HTTP 200 OK");
await Task.CompletedTask;
};
RequestDelegate pipeline = async (context) =>
{
await middleware1(context);
await middleware2(context);
await endpoint(context);
};
var httpContext = new HttpContext();
await pipeline(httpContext);
Console.WriteLine("\n--- Pipeline Finished ---");
}
}
Real ASP.NET Core middleware order
var app = builder.Build();
// ORDER IS CRITICAL
app.UseExceptionHandler("/Error");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();